package com.christianposta.learnddd.domain.model.handling;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.lang.Validate;

import com.christianposta.learnddd.domain.shared.ValueObject;

public class HandlingHistory implements ValueObject<HandlingHistory> {
	
	private List<HandlingEvent> events;
	
	public static final HandlingHistory EMPTY = new HandlingHistory(Collections.<HandlingEvent>emptyList());

	
	public HandlingHistory(final Collection<HandlingEvent> events){
		Validate.notNull(events);
		Validate.noNullElements(events);
		
		this.events = new ArrayList(events);
	}
	

	/**
	 * Get the entire list of distinct events (remove duplicates if they occur) and
	 * order them by completion time.
	 * 
	 * @return
	 */
	public List<HandlingEvent> distinctEventsByCompletionTime(){
		final List<HandlingEvent> ordered = new ArrayList<HandlingEvent>(
			new HashSet<HandlingEvent>(this.events)	
		);
		
		Collections.sort(ordered, BY_COMPLETION_TIME_COMPARATOR);
		return Collections.unmodifiableList(ordered);
	}
	
	public HandlingEvent mostRecentlyCompletedEvent(){
		final List<HandlingEvent> distinct = distinctEventsByCompletionTime();
		
		if(distinct.isEmpty()){
			return null;
		}
		else {
			return distinct.get(distinct.size() - 1);
		}
		
	}
	
	public boolean sameValueAs(HandlingHistory other) {
		return other != null && this.events.equals(other.events);
	}
	
	
	@Override
	public boolean equals(Object obj) {

		if(obj == this) return true;
		if(obj == null || obj.getClass() != getClass()) return false;
		
		HandlingHistory other = (HandlingHistory)obj;
		return sameValueAs(other);
	}
	
	@Override
	public int hashCode() {
		return this.events.hashCode();
	}
	
	private static final Comparator<HandlingEvent> BY_COMPLETION_TIME_COMPARATOR =
		new Comparator<HandlingEvent>() {

			public int compare(HandlingEvent he1, HandlingEvent he2) {
				return he1.completionTime().compareTo(he2.completionTime());
			}
			
		};
}
